package com.whfc.emp.manager.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.config.annotation.NacosValue;
import com.whfc.common.util.MathUtil;
import com.whfc.emp.dao.*;
import com.whfc.emp.dto.train.TrainPaperDTO;
import com.whfc.emp.dto.train.TrainRecordDTO;
import com.whfc.emp.dto.train.TrainRecordEmpDTO;
import com.whfc.emp.dto.train.TrainRecordFileDTO;
import com.whfc.emp.entity.*;
import com.whfc.emp.enums.TrainBoxMsgType;
import com.whfc.emp.enums.TrainSource;
import com.whfc.emp.manager.TrainBoxManager;
import com.whfc.fuum.service.SysDictService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * 培训箱
 *
 * @author qzexing
 * @version 1.0
 * @date 2021-08-26 18:00
 */
@Service
public class TrainBoxManagerImpl implements TrainBoxManager {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private static final String TRAIN_CODE = "train";


    @DubboReference(interfaceClass = SysDictService.class, version = "1.0.0")
    private SysDictService sysDictService;

    @Autowired
    private AppTrainMapper appTrainMapper;

    @Autowired
    private AppTrainEmpMapper appTrainEmpMapper;

    @Autowired
    private AppTrainAttachmentMapper appTrainAttachmentMapper;

    @Autowired
    private AppTrainPaperMapper appTrainPaperMapper;

    @Autowired
    private AppEmpMapper appEmpMapper;

    @Autowired
    private AppTrainFailDataMapper appTrainFailDataMapper;

    @NacosValue("${emp.enter.train.type.id}")
    private Integer enterTrainTypeId;

    @Override
    public void addTrainRecord(List<TrainRecordDTO> trainRecordList) {
        logger.info("同步培训记录, record:{}", trainRecordList);
        if (trainRecordList == null || trainRecordList.isEmpty()) {
            return;
        }
        //保存培训记录
        for (TrainRecordDTO record : trainRecordList) {
            try {
                AppTrain appTrain = appTrainMapper.selectByGuid(record.getId());
                if (appTrain != null) {
                    logger.info("该记录已保存.");
                    continue;
                }
                appTrain = new AppTrain();
                appTrain.setGuid(record.getId());
                appTrain.setDeptId(record.getDeptId());
                Integer trainType = sysDictService.getOrSet(TRAIN_CODE, record.getTrainType());
                appTrain.setTrainType(trainType);
                appTrain.setOrganizer(record.getTrainPrincipal());
                appTrain.setName(record.getRecordName());
                appTrain.setDate(record.getTrainStartDate());
                //时长转换  培训箱单位 秒    本地培训时长单位 小时
                Integer courseDuration = record.getCourseDuration();
                double duration = 0D;
                if (courseDuration != null) {
                    duration = MathUtil.round(courseDuration * 1.0 / 3600, 2);
                }
                appTrain.setDuration(duration);
                appTrain.setTrainer(record.getTrainPrincipal());
                appTrain.setContent(record.getTrainContent());
                appTrain.setSource(TrainSource.TRAIN_BOX.getCode());
                appTrain.setState(1);
                appTrainMapper.insertSelective(appTrain);
            } catch (Exception e) {
                logger.info("train-info:{}", record);
                logger.error("保存培训记录失败.", e);
                //失败数据处理
                saveFailData(record, TrainBoxMsgType.TRAIN_RECORD, e.getMessage());
            }
        }

    }

    @Override
    public void addTrainEmp(List<TrainRecordEmpDTO> trainRecordEmpList) {
        logger.info("同步培训人员, recordEmp:{}", trainRecordEmpList);
        if (trainRecordEmpList == null || trainRecordEmpList.isEmpty()) {
            return;
        }
        for (TrainRecordEmpDTO recordEmp : trainRecordEmpList) {
            try {
                String recordId = recordEmp.getRecordId();
                AppTrain appTrain = appTrainMapper.selectByGuid(recordId);
                if (appTrain == null) {
                    logger.error("未找到该培训记录, trainRecordEmp:{}", recordEmp);
                    //失败数据处理
                    saveFailData(recordEmp, TrainBoxMsgType.TRAIN_RECORD_EMP, "未找到该培训记录, recordId:" + recordId);
                    continue;
                }
                String identifyId = recordEmp.getIdentifyId();
                Integer empId = null;
                String empName = recordEmp.getEmpName();
                AppEmp emp = appEmpMapper.selectByDeptIdAndIdCardNo(recordEmp.getDeptId(), identifyId);


                AppTrainEmp trainEmp = new AppTrainEmp();
                trainEmp.setTrainId(appTrain.getId());

                //分数处理
                Integer score = recordEmp.getScore();
                if (score != null && score > 0) {
                    trainEmp.setScore(score * 1.0);
                }
                //是否通过
                trainEmp.setPassFlag(recordEmp.getIsPass());
                if (emp != null) {
                    empId = emp.getId();
                    empName = emp.getEmpName();
                    //如果当前培训是 入场三级教育  需要更新人员 入场三级教育培训状态
                    if (enterTrainTypeId.equals(appTrain.getTrainType())) {
                        appEmpMapper.updateEmpEnterTrainFlag(empId, 1);
                    }
                }
                trainEmp.setEmpId(empId);
                trainEmp.setEmpName(empName);
                trainEmp.setTrainPeriod(recordEmp.getTrainPeriod());
                trainEmp.setTotalScore(recordEmp.getTotalScore());
                trainEmp.setPassScore(recordEmp.getPassScore());
                trainEmp.setExamNo(recordEmp.getExamNo());
                trainEmp.setExamCount(recordEmp.getExamCount());
                appTrainEmpMapper.insertSelective(trainEmp);
            } catch (Exception e) {
                logger.info("train-record-emp:{}", recordEmp);
                logger.error("保存培训人员失败.", e);
                //失败数据处理
                saveFailData(recordEmp, TrainBoxMsgType.TRAIN_RECORD_EMP, e.getMessage());
            }
        }
    }

    @Override
    public void addTrainPaper(List<TrainPaperDTO> trainPaperList) {
        logger.info("同步培训试卷, trainPaper:{}", trainPaperList);
        if (trainPaperList == null || trainPaperList.isEmpty()) {
            return;
        }
        //数据处理
        for (TrainPaperDTO trainPaper : trainPaperList) {
            try {
                AppTrainPaper paper = new AppTrainPaper();
                String recordId = trainPaper.getRecordId();
                AppTrain appTrain = appTrainMapper.selectByGuid(recordId);
                if (appTrain == null) {
                    logger.error("未找到该培训记录, trainRecordEmp:{}", trainPaper);
                    //失败数据处理
                    saveFailData(trainPaper, TrainBoxMsgType.TRAIN_RECORD_PAPER, "未找到该培训记录, recordId:" + recordId);
                    continue;
                }
                BeanUtils.copyProperties(trainPaper, paper);
                paper.setTrainId(appTrain.getId());
                appTrainPaperMapper.insertSelective(paper);
            } catch (Exception e) {
                logger.info("train-record-paper:{}", trainPaper);
                logger.error("保存培训试卷失败.", e);
                //失败数据处理
                saveFailData(trainPaper, TrainBoxMsgType.TRAIN_RECORD_PAPER, e.getMessage());
            }
        }
    }

    @Override
    public void addTrainFile(List<TrainRecordFileDTO> trainRecordFileList) {
        logger.info("同步培训文件, trainFile:{}", trainRecordFileList);
        if (trainRecordFileList == null || trainRecordFileList.isEmpty()) {
            return;
        }
        //数据处理
        for (TrainRecordFileDTO trainRecordFile : trainRecordFileList) {
            try {
                String recordId = trainRecordFile.getRecordId();
                AppTrain appTrain = appTrainMapper.selectByGuid(recordId);
                if (appTrain == null) {
                    logger.error("未找到该培训记录, trainRecordEmp:{}", trainRecordFile);
                    //失败数据处理
                    saveFailData(trainRecordFile, TrainBoxMsgType.TRAIN_RECORD_FILE, "未找到该培训记录, recordId:" + recordId);
                    continue;
                }
                AppTrainAttachment attachment = new AppTrainAttachment();
                attachment.setTrainId(appTrain.getId());
                attachment.setType(2);
                attachment.setUrl(trainRecordFile.getFileContent());
                appTrainAttachmentMapper.insertSelective(attachment);
            } catch (Exception e) {
                logger.info("train-record-file:{}", trainRecordFile);
                logger.error("保存培训文件失败.", e);
                //失败数据处理
                saveFailData(trainRecordFile, TrainBoxMsgType.TRAIN_RECORD_FILE, e.getMessage());
            }
        }
    }

    @Async
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleFailedData() {
        logger.info("处理培训同步失败数据");
        //处理培训记录的数据
        List<AppTrainFailData> recordList = appTrainFailDataMapper.selectByType(TrainBoxMsgType.TRAIN_RECORD.getValue());
        if (!recordList.isEmpty()) {
            List<TrainRecordDTO> list = new ArrayList<>();
            for (AppTrainFailData failData : recordList) {
                String data = failData.getData();
                TrainRecordDTO failedRecord = JSON.parseObject(data, TrainRecordDTO.class);
                list.add(failedRecord);
            }
            //删除旧数据
            appTrainFailDataMapper.delByType(TrainBoxMsgType.TRAIN_RECORD.getValue());
            //数据处理
            this.addTrainRecord(list);
        }
        //处理培训人员
        List<AppTrainFailData> recordEmpList = appTrainFailDataMapper.selectByType(TrainBoxMsgType.TRAIN_RECORD_EMP.getValue());
        if (!recordEmpList.isEmpty()) {
            List<TrainRecordEmpDTO> list = new ArrayList<>();
            for (AppTrainFailData failData : recordEmpList) {
                String data = failData.getData();
                TrainRecordEmpDTO failedRecordEmp = JSON.parseObject(data, TrainRecordEmpDTO.class);
                list.add(failedRecordEmp);
            }
            //删除旧数据
            appTrainFailDataMapper.delByType(TrainBoxMsgType.TRAIN_RECORD_EMP.getValue());
            //数据处理
            this.addTrainEmp(list);
        }
        //处理培训试卷
        List<AppTrainFailData> trainPaperList = appTrainFailDataMapper.selectByType(TrainBoxMsgType.TRAIN_RECORD_PAPER.getValue());
        if (!trainPaperList.isEmpty()) {
            List<TrainPaperDTO> list = new ArrayList<>();
            for (AppTrainFailData failData : trainPaperList) {
                String data = failData.getData();
                TrainPaperDTO failedTrainPaper = JSON.parseObject(data, TrainPaperDTO.class);
                list.add(failedTrainPaper);
            }
            //删除旧数据
            appTrainFailDataMapper.delByType(TrainBoxMsgType.TRAIN_RECORD_PAPER.getValue());
            //数据处理
            this.addTrainPaper(list);
        }
        //处理培训记录文件
        List<AppTrainFailData> trainFileList = appTrainFailDataMapper.selectByType(TrainBoxMsgType.TRAIN_RECORD_FILE.getValue());
        if (!trainFileList.isEmpty()) {
            List<TrainRecordFileDTO> list = new ArrayList<>();
            for (AppTrainFailData failData : trainFileList) {
                String data = failData.getData();
                TrainRecordFileDTO failedTrainFile = JSON.parseObject(data, TrainRecordFileDTO.class);
                list.add(failedTrainFile);
            }
            //删除旧数据
            appTrainFailDataMapper.delByType(TrainBoxMsgType.TRAIN_RECORD_FILE.getValue());
            //数据处理
            this.addTrainFile(list);
        }

    }

    /**
     * 失败记录存储
     *
     * @param failDataObj 失败记录
     * @param type        失败数据类型
     * @param errorMsg    错误信息
     * @param <T>         数据对象
     */
    private <T> void saveFailData(T failDataObj, TrainBoxMsgType type, String errorMsg) {
        if (failDataObj == null) {
            return;
        }
        //失败数据处理
        AppTrainFailData failData = new AppTrainFailData();
        failData.setType(type.getValue());
        failData.setData(JSON.toJSONString(failDataObj));
        failData.setErrorMsg(errorMsg);
        appTrainFailDataMapper.insertSelective(failData);
    }
}
